package com.ccjt.efcfs.repaymentplan;

import com.alibaba.fastjson.JSONObject;
import static com.ccjt.efcfs.constant.CalculateConstant.AMOUNT_PRECISION;
import com.ccjt.efcfs.dto.LoanInfo;
import com.ccjt.efcfs.dto.RepayPlan;
import com.ccjt.efcfs.enums.RepayMothodTypeEnum;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

public class AverageCapitalCalUtils implements ICalculate {

    private static AverageCapitalCalUtils averageCapitalCalUtils;

    public static synchronized AverageCapitalCalUtils getInstance() {
        if (averageCapitalCalUtils == null) {
            averageCapitalCalUtils = new AverageCapitalCalUtils();
        }
        return averageCapitalCalUtils;
    }

    // 样例
    // 个人住房公积金贷款计算
    // 房屋总价：600000元
    // 贷款年数：25年
    // 首付：2成
    // 年利率：3.25%
    //  
    // 计算结果
    // 房款总额：600000元
    // 贷款总额：480000元
    // 首期付款：120000元
    // 期数：300期
    // 
    // 计算方式：等额本金
    // 支付息款：195650元
    // 还款总额：675650元
    // 首月还款：2900元
    @Override
    public JSONObject generationPlan(LoanInfo loan, RepayMothodTypeEnum repayMethod) {
        JSONObject returnJson = null;
        switch (repayMethod) {
            case DEBJ: // 等额本金
                returnJson = calDEBJ(loan);
                break;
            case DEBX: // 等额本息
//                returnJson = calDEBX(loan);
                break;
            case DBDX: // 等本等息
//                returnJson = calDBDX(loan);
                break;
            default:
                returnJson = new JSONObject();
        };
        return returnJson;
    }

    /**
     * 等额本金,把贷款数总额等分，每月偿还同等数额的本金和剩余贷款在该月所产生的利息，这样由于每月的还款本金额固定，而利息越来越少，借款人起初还款压力较大，但是随时间的推移每月还款数也越来越少。
     *
     * 计算公式： 利息计算＝（本金 — 已归还本金累计额）×每月利率 每月还款＝（贷款本金 / 还款月数）+（本金 — 已归还本金累计额）×每月利率
     *
     * 应付总利息 = 首期应付本金×(1+还款月数)×还款月数÷2×每月利率 =
     * (本金÷还款月数)×(1+还款月数)×还款月数÷2×每月利率=本金×(1+还款月数)÷2×每月利率
     */
    private JSONObject calDEBJ(LoanInfo loan) {
        JSONObject json = new JSONObject();
        List<RepayPlan> planList = new ArrayList<RepayPlan>();
        Integer totalPeriods = loan.getPlanPeriods().intValue();
        BigDecimal lastResidualPrincipal = loan.getLoanPrincipal(); // 当前结余本金
        BigDecimal totalRepayInterest = loan.getLoanPrincipal().multiply(loan.getPlanPeriods().add(BigDecimal.ONE)).multiply(loan.getCalRate()).divide(new BigDecimal(2)); // 本金×(1+还款月数)÷2×每月利率
        for (int curPeriod = 1; curPeriod <= totalPeriods; curPeriod++) {
            BigDecimal perRepayInterest = lastResidualPrincipal.multiply(loan.getCalRate());// 本期归还利息=上期结余本金*计算利率

            RepayPlan plan = new RepayPlan();
            plan.setTotalPeriods(totalPeriods); // 总期数
            plan.setCurPeriod(curPeriod); // 当前期数
            plan.setPerRepayPrincipal(loan.getAvgPrincipal().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());// 本期归还本金
            plan.setPerResidualPrincipal(lastResidualPrincipal.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期剩余本金
            plan.setPerRepayInterest(perRepayInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期归还利息
            planList.add(plan);

            // 计算结余本金
            lastResidualPrincipal = lastResidualPrincipal.subtract(loan.getAvgPrincipal());
            // 利息累计
//            totalRepayInterest = totalRepayInterest.add(perRepayInterest);
        }
        json.put("totalPrincipal", loan.getPlanPeriods().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("totalPeriods", totalPeriods);
        json.put("totalInterest", totalRepayInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("data", planList);
        return json;
    }

    /**
     * 等额本息 一、概念： 等额本息的意思是，每月的本金+利息之和相等（其实每个月本金和利息都有变化，并不相等）
     *
     * 本金＝PPMT(各期利率,第几期,总期数,本金）; 利息＝IPMT(各期利率,第几期,总期数,本金）
     * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
    
    private JSONObject calDEBX(LoanInfo loan) {
        JSONObject json = new JSONObject();
        List<RepayPlan> planList = new ArrayList<RepayPlan>();
        Integer totalPeriods = loan.getPlanPeriods().intValue();
        BigDecimal t = loan.getCalRate().add(BigDecimal.ONE).pow(totalPeriods); // 临时：(1＋月利率)＾还款月数
        BigDecimal perRepayPrincipalInterest = loan.getLoanPrincipal().multiply(loan.getCalRate()).multiply(t).divide(t.subtract(BigDecimal.ONE), CAL_PRECISION, RoundingMode.HALF_DOWN); // 每期偿还本息
        System.out.println("(等额本息)每月偿还本息 : " + perRepayPrincipalInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        BigDecimal lastResidualPrincipal = loan.getPrincipal(); // 当前结余本金
        BigDecimal totalRepayInterest = BigDecimal.ZERO; // 利息累计
        for (int curPeriod = 1; curPeriod <= totalPeriods; curPeriod++) {
            BigDecimal perRepayInterest = lastResidualPrincipal.multiply(loan.getCalRate());// 本期归还利息=上期结余本金*计算利率
            BigDecimal perRepayPrincipal = perRepayPrincipalInterest.subtract(perRepayInterest);// 本期归还本金=(等额本息)每期偿还本息 - 本期归还利息

            RepayPlan plan = new RepayPlan();
            plan.setTotalPeriods(totalPeriods); // 总期数
            plan.setCurPeriod(curPeriod); // 当前期数
            plan.setPerRepayPrincipal(perRepayPrincipal.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());// 本期归还本金
            plan.setPerRepayInterest(perRepayInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期归还利息
            plan.setPerResidualPrincipal(lastResidualPrincipal.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期剩余本金
            // 计算下期结余本金 = 当前结余本金 - 本期归还本金
            lastResidualPrincipal = lastResidualPrincipal.subtract(perRepayPrincipal);
            // 利息累计
            totalRepayInterest = totalRepayInterest.add(perRepayInterest);
            planList.add(plan);
        }
        json.put("totalPrincipal", loan.getPrincipal().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("totalPeriods", totalPeriods);
        json.put("totalInterest", totalRepayInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("data", planList);
        return json;
    }
 */
    /**
     * 等本等息 一、概念： 等本等息的意思是，每月的本金相等，利息也相等。
     *
     * 公式：每月偿还本息=贷款本金×(1＋月利率)÷还款期数
    private JSONObject calDBDX(LoanInfo loan) {
        JSONObject json = new JSONObject();
        List<RepayPlan> planList = new ArrayList<RepayPlan>();
        Integer totalPeriods = loan.getPeriods().intValue();
        BigDecimal lastResidualPrincipal = loan.getPrincipal(); // 当前结余本金
        BigDecimal totalRepayInterest = loan.getPrincipal().multiply(loan.getCalRate()).multiply(loan.getPeriods()); // 利息累计
        for (int curPeriod = 1; curPeriod <= totalPeriods; curPeriod++) {
            RepayPlan plan = new RepayPlan();
            plan.setTotalPeriods(totalPeriods); // 总期数
            plan.setCurPeriod(curPeriod); // 当前期数
            plan.setPerRepayPrincipal(loan.getPerAvgPrincipal().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());// 本期归还本金
            plan.setPerRepayInterest(loan.getPerAvgInterest().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期归还利息
            plan.setPerResidualPrincipal(lastResidualPrincipal.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue()); // 本期剩余本金
            // 计算下期结余本金 = 当前结余本金 - 本期归还本金
            lastResidualPrincipal = lastResidualPrincipal.subtract(loan.getPerAvgPrincipal());
            // 利息累计
//            totalRepayInterest = totalRepayInterest.add(loan.getPerAvgInterest());
            planList.add(plan);
        }
        json.put("totalPrincipal", loan.getPrincipal().setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("totalPeriods", totalPeriods);
        json.put("totalInterest", totalRepayInterest.setScale(AMOUNT_PRECISION, RoundingMode.HALF_DOWN).doubleValue());
        json.put("data", planList);
        return json;
    }
     */

}
